# -*- coding: utf-8 -*-
"""
****************************
@Time    : 2021/4/28 8:55
@Author  : Candy
@File    : auth.py
****************************
"""
import base64
import hashlib
import json
import random
import time

from config.db import JWT_NOISE
RANDOM = r"""~!@#$%^&*()_+`1234567890-=qwertyuiop{}\asdfghjkl;'zxcvbnm,/{}|:<>?"""


class MiniJWT:

    def __init__(self):
        self.__noise = JWT_NOISE
        self.__header = {
            "alg": "SHA256",
            "typ": "MiniJWT"
        }

    def build(self, uid, ip, client):
        header = self.__m_encode(self.__header)
        payload = self.__m_encode({"uid": uid, "ip": ip, "client": client, "exp": time.time() + 3600})
        signore = self.__m_sha256(header + payload)
        payload = self.shuffle(''.join([i + RANDOM[random.randint(0, 64)] for i in payload]), 3)
        return header + '.' + payload + '.' + signore

    def shuffle(self, text, count):
        while count:
            old = ''.join([v for i, v in enumerate(text) if i & 1])  # 把偶数位提前（index为奇数）
            no_old = ''.join([v for i, v in enumerate(text) if not i & 1])
            return self.shuffle(old + no_old, count-1)
        return text

    def un_shuffle(self, text, count):
        while count:
            old = text[:len(text)//2]  # 前置向后
            no_old = text[len(text)//2:]  # 后置向前
            text = ''.join([i[0]+i[1] for i in zip(no_old, old)])
            return self.un_shuffle(text, count-1)
        return text

    def check(self, val, now_ip, now_client):
        try:
            header, payload, signore = val.split('.')
            payload = ''.join([v for i, v in enumerate(self.un_shuffle(payload, 3)) if not i & 1])
        except Exception:
            return False, 0
        if self.__m_sha256(header+payload) != signore:
            return False, 0
        info = self.__m_decode(payload)
        if info['ip'] != now_ip or info['client'] != now_client:
            return False, 0
        if info['exp'] < time.time():
            return False, 0
        return True, info['uid']

    def get_aid(self, val):
        try:
            payload = val.split(".")[1]
            payload = ''.join([v for i, v in enumerate(self.un_shuffle(payload, 3)) if not i & 1])
            return self.__m_decode(payload).get('uid', 0)
        except Exception:
            return 0

    def __m_encode(self, val):
        return base64.b64encode(json.dumps(val).encode('utf-8')).decode('utf-8')

    def __m_decode(self, val):
        return json.loads(base64.b64decode(val))

    def __m_sha256(self, val):
        h = hashlib.sha256()
        h.update((val.encode('utf-8') + self.__noise.encode('utf-8')))
        return h.hexdigest()


if __name__ == '__main__':
    m = MiniJWT()
    a = m.build(0, "1", "2")
    print(a)
    status, _ = m.check(a, "1", "2")
    if status:
        print(m.get_aid(a))
    else:
        print('err')
